#### Tendermint + EVM 移植
 evm 版本 =》v1.8.12   = > solidity 0.4.21 ~ 0.4.24

#### 测试合约
```

pragma solidity ^0.4.21;
interface BaseInterface {
    function CurrentVersion() external view returns(string);
}

contract Helloworld {
    uint256 balance;
    event Triggle(address, string);
    mapping(address=>uint256) _mapamount;

    constructor() public {
        balance = 6000000000;
        _mapamount[0] = 100;
        _mapamount[1] = 200;
    }

    function getbalance() public  returns (address, uint256) {
        emit Triggle(msg.sender, "funck");
        return (msg.sender, balance--);
    }

    function onlytest() public{
        _mapamount[1] = 100;
        emit Triggle(msg.sender, "onlytest");
    }

    function setBalance(uint256 tmp) public {
        balance = tmp;
    }

    function getVersion(address contractAddr) public view returns (string) {
        BaseInterface baseClass = BaseInterface(contractAddr);
       return baseClass.CurrentVersion();
    }

}

pragma solidity ^0.4.21;

contract BaseContract {
  address public owner;
 //
 function CurrentVersion() pure public returns(string)  {
     return "BaseContractV0.1";
 }
}

```

### BaseContract
remix编译后的字节码

```
{
	"linkReferences": {},
	"object": "608060405234801561001057600080fd5b506101c6806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632b225f29146100515780638da5cb5b146100e1575b600080fd5b34801561005d57600080fd5b50610066610138565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b506100f6610175565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040805190810160405280601081526020017f42617365436f6e747261637456302e3100000000000000000000000000000000815250905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058202fb1a08ad01df2586aa0d2b4353dc6b24389668bec137e608612d1d4c69360060029",
	"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1C6 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4C JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x2B225F29 EQ PUSH2 0x51 JUMPI DUP1 PUSH4 0x8DA5CB5B EQ PUSH2 0xE1 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x66 PUSH2 0x138 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xA6 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x8B JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0xD3 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0xED JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xF6 PUSH2 0x175 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x40 DUP1 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x10 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x42617365436F6E747261637456302E3100000000000000000000000000000000 DUP2 MSTORE POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x2f 0xb1 LOG0 DUP11 0xd0 SAR CALLCODE PC PUSH11 0xA0D2B4353DC6B24389668B 0xec SGT PUSH31 0x608612D1D4C693600600290000000000000000000000000000000000000000 ",
	"sourceMap": "984:153:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;984:153:0;;;;;;;"
}
```


web3

```
var basecontractContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"CurrentVersion","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]);
var basecontract = basecontractContract.new(
   {
     from: web3.eth.accounts[0],
     data: '0x608060405234801561001057600080fd5b506101c6806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632b225f29146100515780638da5cb5b146100e1575b600080fd5b34801561005d57600080fd5b50610066610138565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b506100f6610175565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040805190810160405280601081526020017f42617365436f6e747261637456302e3100000000000000000000000000000000815250905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058202fb1a08ad01df2586aa0d2b4353dc6b24389668bec137e608612d1d4c69360060029',
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

```

### Helloworld 编译后字节码


#### 运行
遇到的问题很多
 - 编译 出现cc1.exe: sorry, unimplemented: 64-bit mode not compiled in
  go version go1.13.4 windows/amd64
  下载 64位 https://sourceforge.net/projects/mingw-w64/
  需要配置GCC_HOME 和 PATH= D:\install\mingw64\bin 即可编译  ;还要注意 IDEA 工具是否使用的这个路径， where gcc 查看
  或者重启电脑

```
go env
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Administrator\AppData\Local\go-build
set GOENV=C:\Users\Administrator\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=D:\install\GoPath
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOROOT=D:\install\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=D:\install\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=E:\ws\gows\svm\go.mod
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\ADMINI~1\AppData\Local\Temp\go-build617201350=/tmp/go-build -gno-record-gcc-s
witches


```


# panic: invalid opcode 0xfd
  可能是 操作码解释器 要选择最全的。
   最后一个最全
  ```

  var (
  	frontierInstructionSet       = newFrontierInstructionSet()
  	homesteadInstructionSet      = newHomesteadInstructionSet()
  	byzantiumInstructionSet      = newByzantiumInstructionSet()
  	constantinopleInstructionSet = newConstantinopleInstructionSet()
  )


  // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
  func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
  	// 都注释
  	/*if contract.CodeAddr != nil {
  		precompiles := PrecompiledContractsHomestead
  		if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
  			precompiles = PrecompiledContractsByzantium
  		}
  		if p := precompiles[*contract.CodeAddr]; p != nil {
  			return RunPrecompiledContract(p, input, contract)
  		}
  	}*/
  	return evm.interpreter.Run(contract, input)
  }
  ```



```

func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
	// We use the STOP instruction whether to see
	// the jump table was initialised. If it was not
	// we'll set the default jump table.
	//  根据 ChainConfig 判断使用哪一种解释器指令
	if !cfg.JumpTable[STOP].valid {
		switch {
		case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
			cfg.JumpTable = constantinopleInstructionSet
		case evm.ChainConfig().IsByzantium(evm.BlockNumber):
			cfg.JumpTable = byzantiumInstructionSet
		case evm.ChainConfig().IsHomestead(evm.BlockNumber):
			cfg.JumpTable = homesteadInstructionSet
		default:
			cfg.JumpTable = frontierInstructionSet
		}
	}
```

#### idea 使用solidity 插件
1. idea 安装
2. npm install -g solc  没有 solcjs.exe 就直接下载windows 二进制文件
  https://github.com/ethereum/solidity/releases/tag/v0.4.21
3. 打开  idea  tools ,添加外部工具


## TesvmontractDeploy 测试结果
```
=== RUN   TesvmontractDeploy
====合约世界状态
accAddr: 0x00000000000000000000000000000000123456AB, type: 0 , balance:3999999962718, nonce:2
accAddr: 0x2d9e9AeC81e953Ef341154Fd5Df9d8eCD5161C97, type: 1 , balance:0, nonce:0
accAddr: 0x4698439C9611E42691a06C047A87e7cC84A42BdF, type: 1 , balance:0, nonce:0
 0x00000000000000000000000000000000123456AB 有 5999999962718 个token
contract address: 0xDc6ab9f81e16BaA35C697e817B79F2284A978B99
runtime code: 606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063771602f7146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b60008183019050929150505600a165627a7a7230582026d89f67b6069442b56e389740a7f062e1351790efa411b61b4d8b7a95c535510029
实际消费gas 37282 , 剩余 9999962718
====合约世界状态
accAddr: 0x4698439C9611E42691a06C047A87e7cC84A42BdF, type: 1 , balance:0, nonce:0
accAddr: 0xDc6ab9f81e16BaA35C697e817B79F2284A978B99, type: 1 , balance:0, nonce:0
accAddr: 0x00000000000000000000000000000000123456AB, type: 0 , balance:5999999925436, nonce:3
accAddr: 0x2d9e9AeC81e953Ef341154Fd5Df9d8eCD5161C97, type: 1 , balance:0, nonce:0
--- PASS: TesvmontractDeploy (23.28s)
PASS
```

函数的hash 可以通过remix 编译后的 FUNCTIONHASHES 查看

```
FUNCTIONHASHES
{
    "771602f7": "add(uint256,uint256)",
    "4d9b3d5d": "getbalance()",
    "7991d3a3": "setbalance(uint256)"
}

```
RUNTIME BYTECODE 也可以看到


StateDB接口
```

type StateDB interface {
  // 创建账户函数 表明evm需要你执行创建一个新的账户体系
	CreateAccount(common.Address)

  // 减去一个账户的余额
	SubBalance(common.Address, *big.Int)
	// 添加一个账户的余额
	AddBalance(common.Address, *big.Int)
	// 获取一个账户的余额
	GetBalance(common.Address) *big.Int
  // 获取账户的nonce 因为以太坊要根据nonce在决定交易的执行顺序和合约地址的生成
	GetNonce(common.Address) uint64
	// 更新合约的nonce
	SetNonce(common.Address, uint64)

  // 获取合约地址的整个合约代码的hash值
	GetCodeHash(common.Address) common.Hash
	// 获取合约代码
	GetCode(common.Address) []byte
	// 设置合约代码
	SetCode(common.Address, []byte)
	// 获取合约代码的大小
	GetCodeSize(common.Address) int
  // 获取和添加偿还金额
	AddRefund(uint64)
	GetRefund() uint64
  // 注意这两个函数很重要 其实质就是相当于数据库的select和update
  // 一个智能合约的全局静态数据的读取和写入就是通过这两个函数
	GetState(common.Address, common.Hash) common.Hash
	SetState(common.Address, common.Hash, common.Hash)

  // 合约账户自杀 或者是否已经自杀 主要是以太坊的一个机制 自杀的合约会给与退费
	Suicide(common.Address) bool
	HasSuicided(common.Address) bool

  // 判断一个合约是否存在
	Exist(common.Address) bool
	// 判断合约是否为空
	// is defined according to EIP161 (balance = nonce = code = 0).
	Empty(common.Address) bool

	RevertToSnapshot(int)
	Snapshot() int

  // 此函数就是在我们在智能合约中执行emit命令时调用的
	AddLog(*types.Log)
	AddPreimage(common.Hash, []byte)

  // 这个接口在evm中没有使用到 我们可以写一个空函数
	ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
}


```

生成完整一些的文件
```
solc --help
solc -o a --abi  --bin --ast --asm --hashes  --metadata helloworld.sol

```


###  evm-tools 教程
安装： https://github.com/CoinCulture/evm-tools/blob/master/INSTALL.md
使用:  https://github.com/CoinCulture/evm-tools/blob/master/analysis/guide.md


Finally, let's call the get function. First, we get the functionid from solc:
```
$ solc --hashes add.sol
======= Addition =======
Function signatures:
6d4ce63c: get()
a5f3c23b: add(int256,int256)
Now we can call the contract:

$ evm --datadir evm-data --to 0x1F2A98889594024BFFDA3311CBE69728D392C06D --input 6d4ce63c
Datadir already exists
Loading database
Loading root hash F3C30A7CD9769C45590C236816F2714E96198DBD7FEC33AE892E861816F548B2
Loaded account for receiver 1F2A98889594024BFFDA3311CBE69728D392C06D
CODE: 606060405260E060020A60003504636D4CE63C81146024578063A5F3C23B146031575B005B6000546060908152602090F35B60243560043501600055602256
VM STAT 0 OPs
OUT: 0x0000000000000000000000000000000000000000000000000000000000000009
```
